package com.huqing.icu.rentchatrag.controller;

import com.huqing.icu.rentchatrag.utils.VectorDistanceUtils;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.document.Document;
import org.springframework.ai.openai.OpenAiEmbeddingModel;
import org.springframework.ai.reader.ExtractedTextFormatter;
import org.springframework.ai.reader.pdf.PagePdfDocumentReader;
import org.springframework.ai.reader.pdf.config.PdfDocumentReaderConfig;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

import java.util.Arrays;
import java.util.List;

/**
 * @Description AI对话接口
 * @Author huqing
 * @Date 2025/5/31 17:43
 **/
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/chat")
@Tag(name = "AI对话接口")
public class ChatController {

    private final ChatClient chatClient;

    private final ChatMemory chatMemory;

    //如果不写produces = "text/html;charset=utf-8"，大模型输出会乱码
    @GetMapping(value = "/chat", produces = "text/html;charset=utf-8")
    public Flux<String> chat(String prompt) {
        return chatClient.prompt().user(prompt).stream().content();
    }

    @GetMapping(value = "/v1", produces = "text/html;charset=utf-8")
    public Flux<String> chatV1(@RequestParam("prompt") String prompt) {
        //String prompt = "你是谁";
        String chatId = "1";
        //前端传给我的会话ID，需要传给advisors，让advisors去管理，也就是添加会话ID到AdvisorsContext上下文中,根据不同的会话ID做用户会话的区分
        return chatClient.prompt().user(prompt).advisors(o -> o.param(ChatMemory.CONVERSATION_ID, chatId)).stream().content();
    }


    //向量
    @Autowired
    private OpenAiEmbeddingModel openAiEmbeddingModel;

    @GetMapping(value = "/v2", produces = "text/html;charset=utf-8")
    public String testEmbedding() {

        //测试数据，用来查询的文本
        String query = "端午应该做什么";
        //用来做比较的文本
        String[] texts = new String[]{
                "端午要去广州猎德村",
                "去看划龙舟"
        };

        //先将查询文本向量化
        float[] queryVector = openAiEmbeddingModel.embed(query);
        //再将比较文本向量化，放到一个数组
        List<float[]> textVectors = openAiEmbeddingModel.embed(Arrays.asList(texts));

        //比较欧式距离，把查询文本自己与自己做比较，相似度肯定是最高的,注意，这里计算欧式距离，值越小，相似度越高
        double v = VectorDistanceUtils.euclideanDistance(queryVector, queryVector);
        System.out.println(v);

        //把查询文本和其他文本做比较
        for (float[] textVector : textVectors) {
            double v1 = VectorDistanceUtils.euclideanDistance(queryVector, textVector);
            System.out.println(v1);
        }
        return "";
    }


    @Autowired
    private VectorStore vectorStore;

    //把pdf文件写入向量数据库,读取pdf文件需要引入依赖：spring-ai-pdf-document-reader
    private void writeFileToVectorStore() {

        Resource resource = (Resource) new FileSystemResource("");

        //创建PagePdfDocumentReader
        /*PagePdfDocumentReader reader = new PagePdfDocumentReader(
                resource,  //文件源
                PdfDocumentReaderConfig.builder()
                        .withPageExtractedTextFormatter(ExtractedTextFormatter.defaults())
                        //每一页pdf作为一个Document,正常应该是按照段落来分
                        .withPagesPerDocument(1)
                        .build()
        );*/

        //创建PagePdfDocumentReader，这段代码，是来自Spring AI官方文档
        PagePdfDocumentReader reader = new PagePdfDocumentReader("U:\\Spring AI教程\\黑马程序员SpringAI\\中二知识笔记.pdf",
                PdfDocumentReaderConfig.builder()
                        .withPageTopMargin(0)
                        //文本格式化器
                        .withPageExtractedTextFormatter(ExtractedTextFormatter.builder()
                                .withNumberOfTopTextLinesToDelete(0)
                                .build())
                        //每一页pdf作为一个Document,值为2则表示每2页来分 正常应该是按照段落来分,
                        .withPagesPerDocument(1)
                        .build());

        //读取PDF文件为Document格式
        List<Document> documents = reader.read();

        //将文本写入向量数据库
        vectorStore.add(documents);

        //搜索
        List<Document> documentList = vectorStore.similaritySearch("论语中教育的目的是什么");

        if (documentList == null) {
            System.out.println("没有搜索到任何内容");
            return;
        }
        for (Document document : documentList) {
            System.out.println(document.getId());
            System.out.println(document.getScore());
            System.out.println(document.getText());
        }

        //搜索方法2
        //similarityThreshold是相似度阈值，比如相似度超过0.6的才查出来
        SearchRequest request = SearchRequest.builder().query("论语中教育的目的是什么").topK(1)
                .similarityThreshold(0.6)
                //过滤条件，内容来源于元数据，document对象有属性metadata
                .filterExpression("file_name == '中二知识笔记.pdf'")
                .build();
        vectorStore.similaritySearch(request);
    }


}
